package gate

import (
	"github.com/golang/protobuf/proto"
	"leaf/core/log"
	. "leaf/core/msg"
	"leaf/core/network"
	"net"
	"reflect"
	"sync"
)

type Agent interface {
	SendInnerMsg(data proto.Message)
	SendMsg(data proto.Message)
	Lock()
	ULock()
	LocalAddr() net.Addr
	RemoteAddr() net.Addr
	Close()
	Destroy()
	UserData() interface{}
	SetUserData(data interface{})
}

var AgentMap = map[uint64]Agent{}
var AgentMapMetux sync.RWMutex

func AddAgent(id uint64, agent Agent) bool {
	AgentMapMetux.Lock()
	AgentMap[id] = agent
	AgentMapMetux.Unlock()
	return true
}

func DelAgent(id uint64) bool {
	AgentMapMetux.Lock()
	if _, ok := AgentMap[id]; ok {
		delete(AgentMap, id)
		AgentMapMetux.Unlock()
		return true
	}
	AgentMapMetux.Unlock()
	return false
}

func GetAgent(id uint64) Agent {
	AgentMapMetux.RLock()
	a := AgentMap[id]
	AgentMapMetux.RUnlock()
	return a
}

func AgentDestroy() {
	AgentMapMetux.RLock()
	for _, v := range AgentMap {
		v.Destroy()
	}
	AgentMapMetux.RUnlock()
}

type GatAgent struct {
	conn     network.Conn
	userData interface{}
	mutex    sync.Mutex
	msgLimit map[uint16]int64
}

func (agent *GatAgent) Process(head *MessageHead, msgBytes []byte) {
	msg, err := Processor.ProccessMsg(agent, head, msgBytes)
	if err != nil {
		log.Debug("GatAgent run err: %v", err)
		return
	}

	respBytes, err := Marshal(msg.Reply)
	if err != nil {
		log.Debug("GatAgent run err: %v", err)
		return
	}
	agent.conn.WriteMsg(respBytes)
}

func (agent *GatAgent) OnClose() {

}

func (agent *GatAgent) Lock() {
	agent.mutex.Lock()
}

func (agent *GatAgent) ULock() {
	agent.mutex.Unlock()
}

func (agent *GatAgent) SendInnerMsg(msg proto.Message) {
	if msg == nil {
		log.Error("GatAgent send inner msg err:msg is nil")
		return
	}

	err := Processor.ProccessInnerMsg(agent, msg)
	if err != nil {
		log.Error("GatAgent send inner msg err:%v", err)
		return
	}
}

func (agent GatAgent) SendMsg(data proto.Message) {
	var msg = NewMessage(0, data)
	if msg == nil {
		log.Error("GatAgent sendmsg err:msg not find,msg:%v", reflect.TypeOf(data).Name())
		return
	}

	bytes, err := Marshal(msg)
	if err != nil {
		log.Error("GatAgent sendmsg err: %v", err)
		return
	}
	agent.WriteMsg(bytes)
}

func (agent *GatAgent) WriteMsg(data []byte) {
	err := agent.conn.WriteMsg(data)
	if err != nil {
		log.Error("GatAgent writemsg error: %v", err)
	}
}

func (agent *GatAgent) LocalAddr() net.Addr {
	return agent.conn.LocalAddr()
}

func (agent *GatAgent) RemoteAddr() net.Addr {
	return agent.conn.RemoteAddr()
}

func (agent *GatAgent) Close() {
	agent.conn.Close()
}

func (agent *GatAgent) Destroy() {
	agent.conn.Destroy()
}

func (agent *GatAgent) UserData() interface{} {
	return agent.userData
}

func (agent *GatAgent) SetUserData(data interface{}) {
	agent.userData = data
}
